package com.hmdp.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.entity.Shop;
import com.hmdp.exception.WebException;
import com.hmdp.mapper.ShopMapper;
import com.hmdp.service.IShopService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.concurrent.TimeUnit;

import static com.hmdp.utils.RedisConstants.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {

    private final RedisTemplate<String, Object> redisTemplate;

    private final RedissonClient redissonClient;

    @Override
    public Shop getShopById(Long id) {
        RBloomFilter<Long> shopBloomFilter = redissonClient.getBloomFilter("shopBloomFilter");
        if (!shopBloomFilter.contains(id)) {
            throw new WebException("店铺信息不存在...Bloom");
        }

        String key = CACHE_SHOP_KEY + id;
        Object cacheData = redisTemplate.opsForValue().get(key);

        if (cacheData != null) {
            if ("".equals(cacheData)) {
                throw new WebException("店铺信息不存在...NULL");
            }
            return (Shop) cacheData;
        }

        boolean isLocked = false;
        RLock lock = redissonClient.getLock(LOCK_SHOP_KEY + id);
        try {
            isLocked = lock.tryLock(1, LOCK_SHOP_TTL, TimeUnit.SECONDS);
            if (!isLocked) {
                Object data = redisTemplate.opsForValue().get(key);
                if (data != null && !"".equals(data)) {
                    return (Shop) data;
                }
                throw new WebException("请稍后重试");
            }

            Object data = redisTemplate.opsForValue().get(key);
            if (data != null && !"".equals(data)) {
                return (Shop) data;
            }

            Shop shop = this.baseMapper.selectById(id);
            if (shop == null) {
                redisTemplate.opsForValue().set(key, "", CACHE_NULL_TTL, TimeUnit.MINUTES);
                throw new WebException("店铺信息不存在！");
            }

            redisTemplate.opsForValue().set(key, shop, CACHE_SHOP_TTL, TimeUnit.MINUTES);
            return shop;
        } catch (InterruptedException e) {
            throw new WebException("获取锁失败");
        } finally {
            if (isLocked) {
                lock.unlock();
            }
        }
    }

    @Transactional
    @Override
    public void updateShopById(Shop shop) {
        Long id = shop.getId();
        if (id == null) {
            throw new WebException("店铺ID不能为空");
        }
        super.updateById(shop);
        redisTemplate.delete(CACHE_SHOP_KEY + id);
    }
}
